package com.kaibes.web.encryption;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.kaibes.core.base.util.ArrayUtils;
import com.kaibes.core.base.util.RsaUtils;
import com.kaibes.core.base.util.StringUtils;
import com.kaibes.web.filter.FilterInternal;
import com.kaibes.web.request.RequestBodyListener;

@Order(1)
@Component
public class RsaBodyListener implements RequestBodyListener {

    @Autowired
    private EncryptionUtils encryptionUtils;

    @Override
    public boolean supports(HttpServletRequest request) {
        String type = request.getHeader(EncryptionRes.DATA_ENCRY_TYPE);
        if (type == null) {
            return false;
        }
        type = type.toUpperCase();
        boolean flag = EncryptionRes.RSA.equals(type);
        if (flag) {
            request.setAttribute(EncryptionRes.RSA_PRIVATE_KEY, encryptionUtils.getRsaPrivateKey());
        } else {
            flag = EncryptionRes.RSA_SELF.equals(type);
            if (flag) {
                Object privateKey = request.getAttribute(EncryptionRes.RSA_PRIVATE_KEY);
                if (privateKey == null) {
                    request.setAttribute(EncryptionRes.RSA_PRIVATE_KEY,
                            request.getSession().getAttribute(EncryptionRes.RSA_PRIVATE_KEY));
                }
            }
        }
        return flag;
    }

    @Override
    public byte[] doWithBody(FilterInternal filterInternal, byte[] body) {
        String privateKey = (String) filterInternal.getRequest().getAttribute(EncryptionRes.RSA_PRIVATE_KEY);
        if (privateKey == null) {
            try {
                filterInternal.getResponse().sendError(HttpServletResponse.SC_REQUEST_TIMEOUT);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        } else if (ArrayUtils.isEmptyOrStartsWith(body, '{', '[')) {
            try {
                filterInternal.getResponse().sendError(HttpServletResponse.SC_BAD_REQUEST);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        } else {
            try {
                body = RsaUtils.decrypt(StringUtils.getString(body), privateKey);
            } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException
                    | IllegalBlockSizeException | BadPaddingException | IOException e) {
//                e.printStackTrace();
                body = null;
            }
            return body;
        }
    }

}
